#pragma once 
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <cassert>

#include "../Common/Log.hpp"
#include "../Common/Util.hpp"

//文件版本的题库

const std::string Questions_List = "./questions/questions.list";
const std::string Questions = "./questions";


struct Question{
    std::string _number;    //题号
    std::string _title;     //标题
    std::string _level;     //难度
    int _cpu_limit;         //CPU限制
    int _mem_limit;         //内存限制

    std::string _desc;      //题目的描述
    std::string _header;    //给用户的代码头部(用户看得到的)
    std::string _tail;      //oj模块要拼接到header的测试代码
};

class Model{
public:
    Model(){assert(LoadQuestionsList(Questions_List));}
    ~Model(){}

    //把所有的题目加载到内存！
    bool LoadQuestionsList(const std::string& questions_list){
        std::ifstream in(Questions_List);
        if(!in.is_open()) {
            LOG(FATAL) << "加载题库失败！" << "\n";
            return false;
        }

        std::string line;
        while(std::getline(in, line)){
            //今天这里读取，是不需要换行符的！
            if(line.size() < 5) {
                LOG(WARNING) << "加载部分题目失败, 请检查文件格式" << "\n";
                continue; //不符合的情况
            }

            std::vector<std::string> tokens;
            StringUtil::StringSplit(line, &tokens, " ");
            Question ques;
            ques._number = tokens[0];
            ques._title = tokens[1];
            ques._level = tokens[2];
            ques._cpu_limit = std::stoi(tokens[3]);
            ques._mem_limit = std::stoi(tokens[4]);

            std::string Ques_Num_Path = Questions + "/" + ques._number + "/";
            FileUtil::ReadFromFile(Ques_Num_Path + "desc.txt", &ques._desc, true);
            FileUtil::ReadFromFile(Ques_Num_Path + "header.cpp", &ques._header, true);
            FileUtil::ReadFromFile(Ques_Num_Path + "tail.cpp", &ques._tail, true);

            //添加到内存中进行管理 其实就是哈希
            _questions[ques._number] = ques;
        }
        LOG(INFO) << "加载题库成功" << "\n";
        in.close();
        return true;
    }


    /*下面的获取都是从内存中获取的，也就是model中*/

    //获取单个题目
    bool GetOneQuestion(const std::string& number, Question* q){
        auto it = _questions.find(number);
        if(it == _questions.end()) {
            LOG(ERROR) << "用户获取题目失败，编号: " << number << "\n";
            return false;
        }
        *q = it->second;
        return true;
    }

    //获取所有的题目
    bool GetAllQuestion(std::vector<Question>* out){
        if(_questions.size() == 0) {
            LOG(ERROR) << "用户获取题库失败" << "\n";
            return false;
        }
        for(auto& it : _questions) out->push_back(it.second);
        return true;
    }

private:
    //这里是一个以string为题号 作为key的哈希，映射的是该题号对应的题目(一些细节)
    std::unordered_map<std::string, Question> _questions;
};